package com.fzkj.juc.cas;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.atomic.AtomicStampedReference;

/**
 * @DESCRIPTION 演示ABA问题
 */
public class ABADemo {

    public static void main(String[] args) {
//        aba();
//        reference();
        ABAResolve();
    }

    public static void aba(){
        AtomicInteger num = new AtomicInteger(5);
        new Thread(() -> {
            try {
                TimeUnit.SECONDS.sleep(4);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            num.compareAndSet(5, 97);
            System.out.println("AAA线程将num的值修改为了 -> " + num);
        }, "AAA").start();

        new Thread(() -> {
            num.compareAndSet(5, 98);
            System.out.println("BBB线程将num的值修改为了 -> " + num);

            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            // 1秒后BBB线程将值修改回来
            num.compareAndSet(98, 5);
            System.out.println("BBB线程将num的值修改为了 -> " + num);
        }, "BBB").start();

        try {
            TimeUnit.SECONDS.sleep(8);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("num 最后的值是 -> " + num);
    }

    public static void reference(){
        User u1 = new User("1" ,"name1");
        User u2 = new User("2", "name2");

        AtomicReference userReference = new AtomicReference<>();
        userReference.set(u1);

        // 比较并交换
        boolean b = userReference.compareAndSet(u1, u2);
        System.out.println(b + "\t d当前值是 -> " + userReference.get().toString());
        System.out.println(userReference.compareAndSet(u1, u2));
    }

    public static void ABAResolve(){
        AtomicStampedReference<Integer> num = new AtomicStampedReference<>(5, 1);
        new Thread(() -> {
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println(num.compareAndSet(5, 97, 1, 2));
            System.out.println("AAA线程将num的值修改为了 -> " + num.getReference().toString());
        }, "AAA").start();

        new Thread(() -> {
            System.out.println(num.compareAndSet(5, 98, 1, 2));
            System.out.println("BBB线程将num的值修改为了 -> " + num.getReference().toString());
        }, "BBB").start();

        try {
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("num 最后的值是 -> " + num.getReference().toString());
        System.out.println();
    }

    static class User {
        String id;
        String name;
        public User(String id, String name){
            this.id = id;
            this.name = name;
        }

        @Override
        public String toString() {
            return "User [id = " + id  + ", name = " + name + "]";
        }
    }
}

